package com.satis.compose.get.processor

import com.satis.compose.get.annotation.PageRoute
import com.satis.compose.get.annotation.Param
import com.squareup.kotlinpoet.*
import java.lang.annotation.ElementType
import javax.annotation.processing.Messager
import javax.lang.model.element.Element
import javax.lang.model.element.ExecutableElement
import javax.lang.model.util.Elements
import javax.swing.text.View
import javax.tools.Diagnostic

/**
 * @author sunshaobei on 2023/3/25
 */
class PageStoreCreator(
    val elements: Set<Element>, val elementUtils: Elements, val moduleName: String,val mLogger: Messager?
) {

    fun generateFunSpec(): FunSpec {
        val navGraphBuilder = ClassName("androidx.navigation", "NavGraphBuilder")
        val experimentalAnimationApi =
            ClassName("androidx.compose.animation", "ExperimentalAnimationApi")
        val optIn = AnnotationSpec.builder(Class.forName("kotlin.OptIn") as Class<out Annotation>)
            .addMember("%T::class", experimentalAnimationApi).build()
        val builder = FunSpec.builder("${moduleName}ComposePages").addAnnotation(optIn)
            .receiver(navGraphBuilder)
        for (element in elements) {
            val executableElement = element as ExecutableElement
            val defined = ClassName("com.satis.compose.get.navigator", "definedPage")
            val pageRoute = ClassName("com.satis.compose.get.annotation", "PageRoute")
            val packageElement = elementUtils.getPackageOf(
                executableElement
            )
            val compose = ClassName(
                packageElement.qualifiedName.toString(), executableElement.simpleName.toString()
            )

            val annotation = executableElement.getAnnotation(PageRoute::class.java)
            //方法参数
            val decodeFormUrl = ClassName("com.satis.compose.get.navigator","decodeFormUrl")
            var params: StringBuilder = StringBuilder()
            val paramsClassNames = arrayListOf<Any>()
            paramsClassNames.add(compose)
            // nav定义参数
            val navArgument = ClassName("androidx.navigation", "navArgument")
            val navType = ClassName("androidx.navigation", "NavType")
            val navArgumentNames = arrayListOf<Any>()
            val navArguments: StringBuilder = StringBuilder()
            navArgumentNames.add(defined)
            navArgumentNames.add(pageRoute)
            navArgumentNames.add(pageRoute)
            navArgumentNames.add(pageRoute)
            navArgumentNames.add(pageRoute)
            //路由地址拼接
            val routeArguments: StringBuilder = StringBuilder()

            executableElement.parameters.forEach {
                val paramAnnotation = it.getAnnotation(Param::class.java)
                val typeName = it.asType().asTypeName().javaToKotlinType()

                val simpleName = it.simpleName
                if (paramAnnotation != null) {
                    val key = paramAnnotation.key
                    if (params.isNotBlank()) {
                        params.append(",")
                    }
                    params.append(simpleName)
                    params.append("=")
                    params.append("it.arguments!!.getString(\"$key\")!!")
                    if (typeName != String::class.asTypeName()){
                        when (typeName) {
                            Int::class.asTypeName() -> {
                                params.append(".toInt()")
                            }
                            Long::class.asTypeName() -> {
                                params.append(".toLong()")
                            }
                            Boolean::class.asTypeName() -> {
                                params.append(".toBoolean()")
                            }
                            else -> {
                                params.append(".%T<%T>()")
                                paramsClassNames.add(decodeFormUrl)
                                paramsClassNames.add(typeName)
                            }
                        }
                    }
                    navArguments.append("%T(\"$key\"){ type = %T.StringType}")
                    navArgumentNames.add(navArgument)
                    navArgumentNames.add(navType)

                    if (navArguments.isNotBlank()) {
                        navArguments.append(",\n")
                    }
                    if (routeArguments.isBlank()){
                        routeArguments.append("/?")
                    }else{
                        routeArguments.append("&")
                    }
                    routeArguments.append("$key={$key}")
                } else {
                    val paramType = it.asType().asTypeName().javaToKotlinType()
                    if (paramType.toString() == "android.os.Bundle"){
                        if (params.isNotBlank()) {
                            params.append(",")
                        }
                        params.append(simpleName)
                        params.append("=")
                        params.append("it.arguments!!")
                    }
                }
            }
            builder.beginControlFlow(
                "%T(" +
                        "\nroute=\"${annotation.route+routeArguments.toString()}\"," +
                        "\nenter=%T.Animation.${annotation.enter}," +
                        "\nexit=%T.Animation.${annotation.exit}," +
                        "\npopEnter=%T.Animation.${annotation.popEnter}," +
                        "\npopExit=%T.Animation.${annotation.popExit}," +
                        "\narguments=listOf($navArguments))",
                    *navArgumentNames.toArray()
                )
            builder.addStatement("%T(${params})", *paramsClassNames.toArray())
                .endControlFlow()

        }

        return builder.build()

    }
}